//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using OpenLS.Chart.Internals;
using OpenLS.Core.Serialization;

namespace OpenLS.Chart
{
    public class BarSeries : Series, INumericValuesProvider, IDataPointOwner, IDataLabelsOwner
    {
       

        private DataSource _cat;
        private DataLabels _dlbls;
        private readonly DataPoints _dPts = new DataPoints();
        private ErrorBars _errorBars;
        private bool _invertIfNegative;
        private PictureOptions _pictureOptions;
        private ChartShape? _shape ;
        private readonly ObservableCollection<TrendLine> _trendLines = new ObservableCollection<TrendLine>();

        private NumericDataSource _val;


        public DataSource Categories
        {
            get { return _cat; }
            set
            {
                _cat = value;
                notifyPropertyChanged("Categories");
            }
        }

        public NumericDataSource Values
        {
            get { return _val; }
            set
            {
                if (_val != null)
                    _val.ValueChanged -= dataSource_ValueChanged;
                _val = value;
                notifyPropertyChanged("Values");
                if (_val != null)
                    _val.ValueChanged += dataSource_ValueChanged;
            }
        }

        public ChartShape? Shape
        {
            get { return _shape; }
            set
            {
                _shape = value;
                notifyPropertyChanged("Shape");
            }
        }


        public PictureOptions PictureOptions
        {
            get { return _pictureOptions; }
            set
            {
                _pictureOptions = value;
                notifyPropertyChanged("PictureOptions");
            }
        }

        public ErrorBars ErrorBars
        {
            get { return _errorBars; }
            set
            {
                _errorBars = value;
                notifyPropertyChanged("ErrorBars");
            }
        }


        public ObservableCollection<TrendLine> TrendLines
        {
            get { return _trendLines; }
        }

        public bool InvertIfNegative
        {
            get { return _invertIfNegative; }
            set
            {
                _invertIfNegative = value;
                notifyPropertyChanged("InvertIfNegative");
            }
        }

        public DataLabels DataLabels
        {
            get { return _dlbls; }
            set
            {
                _dlbls = value;
                notifyPropertyChanged("DataLabels");
            }
        }

        public DataPoints DataPoints
        {
            get { return _dPts; }
        }

        #region INumericValuesProvider Members

        IEnumerable<NumericValue> INumericValuesProvider.GetValues()
        {
            return Values.NumericValues;
        }


        public event EventHandler ValueChanged;

        #endregion

        private void dataSource_ValueChanged(object sender, EventArgs e)
        {
            if (ValueChanged != null)
                ValueChanged(sender, e);
        }


        internal override void ReadXmlCore(ReadContext context)
        {
            using (var c = context.Read("ser"))
            {
                ReadXmlBase(c);
                _invertIfNegative = c.ReadOptionalElementBooleanAttribute("invertIfNegative", "val", false, true);
                DataPoints.Clear();
                while (c.ReaderLocalName == "dPt")
                {
                    DataPoints.Add(c.ReadElement<DataPoint>());
                }
                PictureOptions = c.ReadOptionalElement<PictureOptions>("pictureOptions");
                DataLabels = c.ReadOptionalElement<DataLabels>(DataLabels.xmlName);
                TrendLines.Clear();
                while (c.ReaderLocalName == TrendLine.xmlName)
                {
                    TrendLines.Add(c.ReadElement<TrendLine>());
                }
                ErrorBars = c.ReadOptionalElement<ErrorBars>(ErrorBars.xmlName);
                Categories = DataSource.ReadOptionalDataSource("cat", c);
                Values = NumericDataSource.ReadNumericDataSource("val", c);
                Shape = c.ReadOptionalElementEnumAttribute<ChartShape>("shape");
                c.EatIf("bubble3D");
                Extension = c.ReadOptionalElement<ExtensionElement>("extLst");
            }
        }

        internal override void WriteXmlCore(WriteContext context)
        {
            using (WriteContext c = context.Write("ser"))
            {
                WriteXmlBase(c);
                c.WriteOptionalElementBooleanAttribute("invertIfNegative", _invertIfNegative, false);
                foreach (IOfficeXmlSerializable pt in _dPts)
                    c.WriteElement(pt);
                c.WriteOptionalElement(PictureOptions);
                c.WriteOptionalElement(DataLabels);
                foreach (TrendLine l in TrendLines)
                    c.WriteElement(l);
                c.WriteOptionalElement(ErrorBars);
                WriteOptionalNumericDataSource("cat", Categories, c);
                WriteNumericDataSource("val", Values, c);
                c.WriteOptionalElementEnumAttribute("shape", Shape);
                c.WriteOptionalElement(Extension);
            }
        }

        internal DataPoint GetDataPoint(int index)
        {
            if (DataPoints == null)
                return null;
            foreach (DataPoint p in DataPoints)
                if (p.Index == index)
                    return p;
            return null;
        }

        internal DataPoint EnsureDataPoint(int index)
        {
            foreach (var point in DataPoints)
            {
                if (point.Index == index)
                    return point;
            }
            DataPoint result = new DataPoint(index);
            DataPoints.Add(result);
            return result;
        }
    }
}